#include "modbus.h"

/**
 * @brief 字节序转换函数
 * @param dst
 * @param src
 * @param len
 * @return int
 */
int conver_endian_long(unsigned char *dst, const unsigned char *src, int len)
{
    int i = 0;

    if (len % 4 != 0)
    {
        printf("err len\n");
        return -1;
    }

    while (i < len)
    {
        dst[i] = src[i + 3];
        dst[i + 1] = src[i + 2];
        dst[i + 2] = src[i + 1];
        dst[i + 3] = src[i];
        i += 4;
    }

    return 0;
}

/**
 * @brief 建立tcp连接
 * @param ip 接收点表的ip
 * @param port 接收点表的port
 * @return int
 */
int create_socket(const char *ip, int port)
{

    int addrlen = sizeof(struct sockaddr);
    struct sockaddr_in serveraddr;

    // 1创建一个套接字--socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }

    // 2指定服务器地址--sockaddr_in
    bzero(&serveraddr, addrlen);
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(ip);
    serveraddr.sin_port = htons(port);

    // 3连接服务器--connect
    if (connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
    {
        perror("connect err");
        return -1;
    }
    return sockfd;
}

/**
 * @brief 01功能码,读取空调和灯的状态
 * @param sockfd
 * @return int
 */
int modbus_func_01(int sockfd)
{

    unsigned char send_buf[32] = {0x02, 0xb7, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02};
    unsigned char recv_buf[128] = {0};
    send(sockfd, send_buf, 12, 0);
    int ret = recv(sockfd, recv_buf, 13, 0);
    if (ret < 0)
    {
        perror("recv err");
        return -1;
    }
    // 00 03 00 00 00 04 01 01 01 01 调试软件返回数据
    int data = *(recv_buf + 9);
    return data;
}

/**
 * @brief 03功能码，读取空调温度
 * @param sockfd
 * @return float
 */
float modbus_func_03(int sockfd)
{

    unsigned char send_buf[128] = {0x02, 0xb7, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x02};
    unsigned char recv_buf[128] = {0};
    send(sockfd, send_buf, 12, 0);
    int ret = recv(sockfd, recv_buf, 13, 0);
    if (ret < 0)
    {
        perror("recv err");
        return -1;
    }
    // 00 06 00 00 00 07 01 03 04 41 73 33 33
    float *p = (float *)(recv_buf + 9); // 将指针偏移到数据位置
    float data;
    conver_endian_long((unsigned char *)&data, (unsigned char *)p, 4);
    return data;
}

/**
 * @brief 04功能码 读取温湿度
 * @param sockfd
 * @return int
 */
int modbus_func_04(int sockfd, float *data)
{
    // 发送命令缓冲区
    unsigned char send_buf[32] = {0x02, 0xb7, 0x00, 0x00, 0x00, 0x06, 0x01, 0x04, 0x00, 0x00, 0x00, 0x04};
    // 接收缓冲区
    unsigned char recv_buf[128] = {0};
    send(sockfd, send_buf, 12, 0);
    int ret = recv(sockfd, recv_buf, 128, 0);

    if (ret < 0)
    {
        perror("recv err");
        return -1;
    }
    float *p = (float *)(recv_buf + 9); // 将指针偏移到数据位置
    conver_endian_long((unsigned char *)data, (unsigned char *)p, 8);

    return 0;
}

/**
 * @brief 写多个保持寄存器
 * 
 * @param sockfd 
 * @param val 
 * @return int 
 */
int modbus_func_16(int sockfd, float val)
{
    int i; 
    union num_t num;
    num.f_val = val;
    unsigned char *p = (unsigned char *)&num.m_val;
    printf("val:%.2f\n", val);
    //发送命令缓冲区
    unsigned char send_buf[32] = {0x02, 0xb7, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x10, 0x00, 0x00, 0x00, 0x02, 0x04};
    for (i = 3; i > 0; i--)
    {
        send_buf[16 - i] = p[i];
    }
    for (i = 0; i < 17; i++)
    {
        //将发送的内容打印成16进制看看
        printf("0x%02X, ", send_buf[i]);
    }
    putchar(10);
    //接收缓冲区
    unsigned char recv_buf[128] = {0};
    send(sockfd, send_buf, 17, 0); 
    //回复报文做判断
    int ret = -1;
    unsigned char right_buf[32] = {0x02, 0xb7, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x10, 0x00, 0x00, 0x00, 0x02};
    ret = strcmp((char *)right_buf, (char *)recv_buf);
    return ret;
}